package com.antifly.common.config;

import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.config.SortedResourcesFactoryBean;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.DatabasePopulator;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 自定义Springboot启动前自动执行SQL文件
 *
 * @author LuoJiaHui
 * @date 2023/4/26 9:47
 * @description
 */
@Configuration
public class CustomizeDataSourceInitializer {

    @Autowired
    private DataSourceProperties dataSourceProperties;

    @Bean
    public DataSourceInitializer dataSourceInitializer(final DataSource dataSource) {
        DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
        dataSourceInitializer.setDataSource(dataSource);
        dataSourceInitializer.setDatabasePopulator(databasePopulator());
        return dataSourceInitializer;
    }

    private DatabasePopulator databasePopulator() {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        resources().forEach(populator::addScript);
        return populator;
    }

    /**
     * 判断业务中是否配置sql;主要做忽略某些配置sql文件时使用
     *
     * @return java.util.List<org.springframework.core.io.Resource>
     * @author Antifly
     * @date 2023/4/26 11:17
     **/
    private List<Resource> resources() {
        List<String> schema = dataSourceProperties.getSchema();
        if (CollUtil.isNotEmpty(schema)) {
            return getResources(schema);
        } else {
            return getResources(Collections.singletonList("classpath:sql/*.sql"));
        }
    }

    /**
     * 根据指定路径加载资源文件
     *
     * @param locations 文件地址
     * @return java.util.List<org.springframework.core.io.Resource>
     * @author Antifly
     * @date 2023/4/26 11:18
     **/
    private List<Resource> getResources(List<String> locations) {
        List<Resource> resources = new ArrayList<>();
        for (String location : locations) {
            for (Resource resource : doGetResources(location)) {
                if (resource.exists()) {
                    resources.add(resource);
                } else {
                    throw new InvalidConfigurationPropertyValueException("spring.datasource.schema", resource,
                            "The specified resource does not exist.");
                }
            }
        }
        return resources;
    }

    /**
     * 读取classPath路径下所有预设sql脚本
     *
     * @param locations 资源文件地址
     * @return org.springframework.core.io.Resource[]
     * @author Antifly
     * @date 2023/4/26 10:34
     **/
    private Resource[] doGetResources(String locations) {
        try {
            SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean(new DefaultResourceLoader(),
                    Collections.singletonList(locations));
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (Exception ex) {
            throw new IllegalStateException("Unable to load resources from " + "classpath:sql/*.sql", ex);
        }
    }
}
